package com.jojo.rateLimiter;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 滑动日志算法
 *
 * @author hpl
 * @since 2024/12/12
 */
public class SlidingLog {

    // 限制的时间窗口大小，单位为秒
    private final int windowSizeInSeconds;

    // 每个窗口内允许的最大请求数
    private final int maxRequests;

    // 存储请求时间戳的队列
    private final Queue<Long> requestTimestamps;

    public SlidingLog(int windowSizeInSeconds, int maxRequests) {
        this.windowSizeInSeconds = windowSizeInSeconds;
        this.maxRequests = maxRequests;
        this.requestTimestamps = new LinkedList<>();
    }

    /**
     * 判断是否允许请求
     * 
     * @return true 如果请求被允许，false 如果请求被拒绝
     */
    public boolean allowRequest() {
        long currentTimestamp = System.currentTimeMillis() / 1000; // 当前时间的秒数

        // 移除过期的请求时间戳
        while (!requestTimestamps.isEmpty() && requestTimestamps.peek() <= currentTimestamp - windowSizeInSeconds) {
            requestTimestamps.poll(); // 移除时间窗口之外的请求
        }

        // 判断当前窗口内请求数是否超过最大限制
        if (requestTimestamps.size() < maxRequests) {
            requestTimestamps.offer(currentTimestamp); // 允许请求，加入当前时间戳
            return true;
        }

        // 超过最大请求数，拒绝请求
        return false;
    }

    public static void main(String[] args) {
        // 创建一个滑动窗口限流器，窗口大小为1秒，最大请求数为5
        SlidingLog rateLimiter = new SlidingLog(5, 5);

        // 模拟连续请求
        for (int i = 1; i <= 10; i++) {
            if (rateLimiter.allowRequest()) {
                System.out.println("Request " + i + " allowed");
            } else {
                System.out.println("Request " + i + " denied");
            }

            // 暂停100毫秒，以模拟请求间的间隔
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
